﻿#pragma once
对网络版计算器的收尾：

对 之前的网络计算器程序 进行守护进程

服务器进程应该变成守护进程
做法1：nohup + . / ........不推荐 不建议 不完美

此时就算关掉了服务类程序的shell  客户端依旧可以和守护进程交互 甚至你把xshell关掉 其他人也可以在自己的电脑上运行客户端 和你的守护进程交互


每次点开登录xshel的时候
①： 都会给该终端打开一个终端文件 向这个文件写入 就是向该终端写入 有截图
②：新启一个bash进程，该进程用来做命令行解释。所以每个终端都有一个bash进程

pts / 0所属项叫做TTY： 代表该bash进程和哪个终端文件相关联  0就代表和0号终端文件关联。所以①②是相互有关联的

而①②操作整合起来就叫做新建一个会话，会话的ID就是会话中的第一个进程，一叫做话首进程，一般就是bash进程 会话ID叫做SID；所以当当前bash进程启动任何程序之后，此进程一定是属于对应bash会话的！此时该程序的SID一定是bash的pid！

而当我们关闭shell的时候，那么会话就会被释放，该会话里面的进程都会被终止退出，这就意味着如果服务端程序位于某个会话中，那么关闭xshell就会让服务端程序终止掉！我们应该避免这种情况的发生！ 这就是守护进程存在的意义！

电脑很卡的时候，不一定需要重启，也可能只需注销，windows中的注销就是释放一个会话，每个用户登陆都是会有自己的会话，注销可以关掉会话里面的进程

所以我们需要把服务端进程放进一个新的会话中，此时我们关闭xshell也不会影响到新的会话了，setsid系统调样接口即可。setsid就会创建一个新的会话，并且让调用该接口的进程成为该会话的话首进程！

但是有一个限制条件，不能被进程组的组长调用setsid接口

进程组：有血缘关系，父子，爷孙，兄弟的进程的整体就叫做进程组！有可能是fork创建的进程，也有可能是管道创建的兄弟进程；进程组中的进程一般会互相协助地完成一个进程！

而我们的服务端程序就是自成一组的，自己是组长，因为它没有具有血缘关系的其他进程！所以我们只需在服务器端代码中，fork之后，里面让父进程退出，此时的子进程就可以调用setsid了，因为子进程不是组长，此时的子进程就是守护进程(精灵进程)，其所属一个独立的会话中，守护进程一定是孤儿进程，所以其的回收也不用在意

我们也不用自己的手动的通过代码去做fork退出父进程等操作，因为可以直接使用daemon接口，哪个进程调用该操作，那么哪个进程就变成守护进程！

-------------------- -
int daemon(int nochdir, int noclose);
nochdir：是否需要更改守护进程的工作目录？要则变到 / 根目录，不则启动所在的路径(cwd)
noclose：是否需要进行输入输出的处理？要则代表012三个流重定向到 / dev / null中，相当于丢弃了守护进程的所有输入输出，

两个参数：0代表要，1代表不要，双重否定表肯定
----------------------
/ dev / null文件，任何Linux系统都会存在的一个文件，特点是读不到任何东西，写进去的东西也会被丢弃

守护进程一般会去关联终端文件，TTY就是问号，本质就是不关心也不需要打印，不需要输入输出！而我们的服务器进程也可以满足这一点，因为我们启动之后，只需从套接字中读取数据和返回数据即可，不需要输出输入什么的。

daemon(0, 0)和daemon(1, 1)，的效果都在截图中，daemon(1, 1)后者虽然也是守护进程，但是其工作目录不变，其仍然和终端文件有关联，输入输出会打印到该终端文件中！

所以我们在服务端main.cc中使用daemon(0, 0)即可，另外我们还想看到日志，所以只需使用enablefile接口，把日志打印到指定的文件中即可，但是一但第一个参数为0，代表你的日志文件将会在根目录中生成，肯定会失败的，所以此时只能由root 或者sudo去运行服务端 才会在根目录生成log.txt
但是我们期望的不是这样，所以一般我们放在 / var / log / 中！

这就叫把服务部署在了云服务器上，守护进程的意义所在

------------------------------------------------------------------------------------ -
应用层协议----->HTTP协议：

不管应用层协议是什么，只要你的传输层用的是TCP协议，则必定离不开序列化和黏报问题的解决策略

虽然我们说, 应⽤层协议是我们程序猿⾃⼰定的.比如之前的Socket程序，我们UDP就明确了协议类型是字符串，之后的TCP我们明确了协议类型是结构体，但是但实际上, 已经有⼤佬们定义了⼀些现成的, ⼜⾮常好⽤的应⽤层协议, 供我们直接参考使⽤.HTTP(超⽂本传输协议)就是其中之⼀

这些大佬定义的协议 远比我们自己定义的强得多 比如http

Q：协议无非就是规定一种类型，再添加报头，还能牛到哪里去？

超⽂本：文本，图片，音频，视频等都可以传输

HTTP协议是⼀个⽆连接、⽆状态的协议，即每次请求都需要建⽴新的连接，
且服务器不会保存客⼾端的状态信息。此话暂时无法理解

HTTP协议虽然是基于TCP协议的，但是两个连接的概念不同，所以TCP的连接不关http的事情 http是无连接的

----------------------------------------
认识URL：统一资源定位符

我们从服务器中获取到的资源，在未被获取之前，存储在哪里，必然实在服务器上的，而Linux下一切皆文件，所以在资源必定是在服务器的文件之中的！所以也可以理解为资源就是一个或多个文件

所以获取资源，就是获取文件的内容，所以先要找到对应的文件，那如何找到对应的文件？根据路径即可？不仅仅需要路径，而是先要找到对应的服务器，ip + port即可！ 再根据路径找到指定文件！这样才可以找到唯一服务器的唯一文件；也就是可以找到互联网中的唯一的资源！

所以一个(URL)网址就是 协议 + ip(port) + 路径，就是一个定位的方式，所以URL叫做统一资源定位符，其中的协议就是我们url中的http或者https

并且URL中的协议不一定只是http / https  也有其他的协议 比如ftp用于下载文件等 应用场景不同 协议不同

细节1：但是问题是我们发现大部分网址的协议都叫做https？？因为https囊括了http，且https更安全，会对数据加密和解密，所以我们先学懂http即可
，这样学习https也更好学

细节2：域名代表ip，会被解析成ip，那端口号呢？一般使用URL网址，则代表port都是明确的，是知名的，已经规定好的，所以不明面显示，省略了；没规定的需要 : 80这样子的书写方式 ，也就是说使用http的端口号一定是80  使用https的端口号一定是443 ，所以对协议做出判断后，会自动拼接上端口号

查询字符串：方法的参数
片段标识符：图片轮转的速度

------------------------------------------
URL的urlencode和urldecode(了解) 截图中有
urlencode：url编码
urldecode：url解码


Q：首先我们搜索的时候 并不是每次都输入一个完整的URL 一般都是搜索关键字 比如直接搜索adcd的时候，此时网页的最上面就可以获取一个对应完整的URL，截图中有，我们发现URL中会使用一些特殊符号，比如路径符号 / 或者： ？// 
所以问题在于万一搜索的关键字就是包含了一些我们URL中使用的特殊符号，比如路径符号 / 或者： ？// 等怎么办呢？会让URL的解析出错吗？

A：首先我们搜索的关键字会出现在kv类型的word中，当关键字设计到特殊符号的时候，此时对应的URL中，会发现这些特殊符号会变成 % 3A % 3F这种形式，这叫编码，首先编码就意味着一个字符对应一个数字，所以urlencode：url编码的方法就是用16进制表示数字，然后前面加一个 %


----------------------------------------
Q：那为什么清华大学也在URL中变成 % E6这种样式了？汉字也是特殊字符？

编码：就是把语言(符号)进行编号罢了，你就是1 我就是2 这样....，所以每个汉字都可以映射到一个数字上，所以ascll码表也是类似的道理，无非就是对英文字母进行编号罢了，而中文就是对汉字进行编号罢了.......一个道理，都是(语言)符号到数字的映射！这就是为什么 % c打印65 是a的原因，因为映射

而ascll码表仅仅是英语这种语言的映射，要想让世界的所有语言都能映射为一个数字，所以有了utf8这种编码方式，其拥有更多的映射关系！各国的语言符号都被编码了！

A：所以为什么清华大学会显示为16进制，因为从编码的角度，任何语言都是符号，符号都会被映射到一个数字(因为计算机只认识二进制....)，而http协议将根据utf8编码的映射得到的数字转化为了16进制再加个 % 而已！

而这种转换为16进制加个 % 号就是https的urlencode和urldecode(转义)
urlencode：url编码
urldecode：url解码

所以url编码和url解码肯定是一个函数功能，我们不需要自己实现，可以直接使用现成的接口 ；

可以用URL编码解码工具进行验证清华大学的映射关系


Q：url中的参数中的word类型对应的k值 如果是涉及到URL中的特殊字符 则会被进行urlencode成为 % 16进制的形式 这个我懂 但是为什么我搜索汉字的时候 word对应的v值也是为 % 16进制的形式 汉字并不是关键字啊！ 其次如果汉字需要urlencode为 % 16进制的形式，那为什么我搜索abcd的时候 word此时对应的v值仍然是abcd 而不是urlencode为 % 16进制的形式？？？？

A：URL编码（Percent - Encoding）并不是对所有字符都进行编码，也不是仅仅对特殊字符进行编码，它有一个安全字符列表。只有在URL的特定部分（如查询参数值）中出现的非安全字符才需要被编码。英文是安全字符，而汉字不是！所以会被编码。这与你搜索的是“关键字”还是“非关键字”无关，只与字符本身在URL规范中的定义有关。


------------------------------------------------------------------------------------ -
3：直接写HTTP的代码

首先HTTP协议，我们肯定要见一下协议的请求和响应是什么样子

我们先获取一下HTTP的请求，对请求直接进行打印，也就是看看HTTP发过来的类型的结构是什么

所以直接使用套接字的封装文件即可，方便！


我们不想再像网络计算器那样 三层结构 而是在服务器类所bind的函数的所在类中，去完成一切额外的操作 所以我们的服务器的回调函数的格式需要改一下，改成参数为一个字符串，返回一个字符串  因为HTTP不需要关心客户端的信息，所以参数仅仅为字符串即可，所以参数就是一个请求，返回就是响应

而想要让参数仅仅只有一个字符串，我们则需要在线程函数中完成数据的IO，避免在回调函数bind的函数中还需要使用fd进行数据IO；所以读写我们就在线程函数中进行，因为我们的服务类的成员变量，也就是那个父类指针正好可以直接调用多态函数，所以我们只是单纯的把服务类回调函数_http_service放在另一个类中；而数据的IO直接在线程函数中进行；顺便封装一下关闭fd的接口 显得优雅一点；而此时线程函数获取到的就是请求，把请求作为参数传给_http_service获取到的返回值就是响应！

为什么要在线程函数去进行IO？会存在读取不完整的情况的？是的，但是我们现在不做安全考虑，因为我们需要学完http才知道怎么使用接口

所以我们现在新建Http.hpp文件，这个文件就是类似于TcpServerMain.cc中的一部分 就是bind的函数的那部分 而剩余的部分在main.cc中
(个人不懂为什么不像之前一样 糅合在一起)

所以下面就是客户端进行发送请求了，而我们完全不需要客户端 因为我们直接可以使用浏览器来充当客户端 只要支持http协议的都可以充当客户端 只需在网址处输入我们服务器程序对应的IP和port，其会自动生成对应的URL去搜索资源，当然我们现在无资源 仅仅是对请求进行打印

此时我们的服务端可以看见客户端发来的信息，因为我们仅仅只是打印了http协议发来的请求；其次_http_service就是在一个类中，该类就是httpserver类，而现在我们只需在_http_service中完成对接收到的请求的打印即可，观察http，其次就是要解决报头和有效载荷的分离问题 以及

其次服务器可以在堆也可以在栈上定义的，智能指针unique默认在堆上，服务器很小可以直接在栈上定义

---------------------------------------- -
首先http协议可以不依靠任何第三方库 比如json 所以移植性高

通过观察http的请求
①：http的请求本质是一行长的字符串！间隔符为\r\n(打印下才会进行换行)  ；其中的第一行叫作请求行，第二行到空行之前叫做请求报头，统称为报头
②：最后一行空行是报头和有效载荷的分割行 现在暂无有效载荷
